package com.day1;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * 客户端与服务端的双向通信
 * 1.客户端和服务端的逻辑处理是均是在启动的时候，
 * 通过给逻辑处理链 pipeline 添加逻辑处理器，来编写数据的读写逻辑
 * 2.客户端连接成功之后会回调到逻辑处理器的 channelActive() 方法，
 * 而不管是服务端还是客户端，收到数据之后都会调用到 channelRead 方法。
 * 写数据调用writeAndFlush方法，客户端与服务端交互的二进制数据载体为 ByteBuf，
 * ByteBuf 通过连接的内存管理器创建，字节数据填充到 ByteBuf 之后才能写到对端。
 *
 * @author leonard
 */
public class NettyServer {

    private static final int port = 8888;

    public static void main(String[] args) {

        //1. 创建启动对象
        final ServerBootstrap serverBootstrap = new ServerBootstrap();

        //2. 创建两个对象,一个用来接收连接线程,一个用来读取接收的线程信息进行业务处理
        //老板是接活的,给打工人去做
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();


        serverBootstrap
                .group(boss, worker)//a.设置线程模型
                .channel(NioServerSocketChannel.class)//b.设置io模型为nio
                //option:给服务端channel设置属性
                //临时存放已完成三次握手请求的队列的长度，若建立频繁可加大容量
                .option(ChannelOption.SO_BACKLOG, 1024)
                //childOption:给每条连接设置一些TCP底层相关的属性
                //开启TCP底层心跳机制
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                /*
                是否开启Nagle算法，
                    true表示关闭，false表示开启，
                    通俗地说，如果要求高实时性，有数据发送时就马上发送，就关闭，
                    如果需要减少发送次数减少网络交互，就开启
                 */
                .childOption(ChannelOption.TCP_NODELAY, true)
                //定义后续每条连接的读写,并做相关的业务处理
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new FirstServerHandler());
                    }
                });


        //绑定端口
        bind(serverBootstrap, port);


    }


    private static void bind(ServerBootstrap serverBootstrap, int port) {
        serverBootstrap.bind(port).addListener(future -> {
            if (future.isSuccess()) {
                System.out.println("端口[" + port + "]绑定成功!");
            } else {
                System.err.println("端口[" + port + "]绑定失败!");
            }
        });
    }
}
